import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DocumentMerger {
    // 计算文件的校验码（使用 MD5 算法）
    public static String calculateChecksum(File file) throws NoSuchAlgorithmException, IOException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = fis.read(buffer))!= -1) {
                md.update(buffer, 0, bytesRead);
            }
        }
        return new BigInteger(1, md.digest()).toString(16);
    }

    public static boolean validateChecksum(File file, String expectedChecksum) throws NoSuchAlgorithmException, IOException {
        String calculatedChecksum = calculateChecksum(file);
        return calculatedChecksum.equals(expectedChecksum);
    }

    public static void mergeFiles(String[] partFilePaths, String outputFilePath, Integer blockSize) throws IOException, NoSuchAlgorithmException {
        byte[] buffer = new byte[blockSize*10];
        int bytesRead;
        long totalBytesWritten = 0;

        try (FileOutputStream fos = new FileOutputStream(outputFilePath);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            int fileIndex = 0;
            for (String partFilePath : partFilePaths) {
                File partFile = new File(partFilePath);
                try (FileInputStream fis = new FileInputStream(partFile);
                     BufferedInputStream bis = new BufferedInputStream(fis)) {
                    while ((bytesRead = bis.read(buffer))!= -1) {//当 bis.read(buffer) 读取的数据量小于 buffer 的大小时，bytesRead 会被赋值为实际读取到的字节数，只要这个值不为 -1，循环就会继续执行。例如，如果 buffer 长度是 1024 字节，但 bis 中只剩下 500 字节的数据，那么这次读取 bytesRead 会被赋值为 500，循环会继续检查是否还有更多数据可读，直到 bis.read(buffer) 返回 -1
                        System.out.println("bytesRead:"+bytesRead);
                        if (fileIndex!=partFilePaths.length-1){
                            bos.write(buffer, 0, blockSize);
                        }else{
                            // 如果读取到的内容包含"CHECKSUM:"，则开始读下一个块的内容
//                            if (new String(buffer, fileContentSize, bytesRead).contains("CHECKSUM:")) {
                                bos.write(buffer, 0, (int) (79755-(blockSize* (partFilePaths.length-1))));
//                                break;
//                            }
                        }
                        System.out.println("第"+fileIndex+"块已读取字节数：" + bytesRead);
                    }
                }
                // 读取并验证校验码
                try (FileInputStream fis = new FileInputStream(partFile);
                     java.io.BufferedReader br = new java.io.BufferedReader(new java.io.InputStreamReader(fis))) {
                    String line;
                    while ((line = br.readLine())!= null) {
                        if (line.startsWith("CHECKSUM:")) {
                            String checksum = line.substring("CHECKSUM:".length());
                            if (!validateChecksum(partFile, checksum)) {
                                throw new IOException("校验失败：" + partFilePath);
                            }
                            break;
                        }
                    }
                }
                fileIndex++;

            }
        }
    }

    public static void main(String[] args) {
        try {
            mergeFiles(new String[]{"output/part_0.bin", "output/part_1.bin", "output/part_2.bin", "output/part_3.bin"}, "output/twoParties.png", 20480);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}